﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Lister;
using SevenZip;
using COFE.Core;
using COFE.IO.SZ.Utils;
using System.IO;
using NUnit.Framework;
using System.Diagnostics;
using COFE.Core.Profile;
using COFE.Core.Utils;
using COFE.Core.Entry;

namespace COFE.IO.SZ
{
    public class SevenZipDirectoryLister : SecondaryDirectoryListerBase<SZEntryInfo>
    {
        #region Constructor            

        public override IInternalFileSystemInfoExA ConvertEntry(IInternalFileSystemInfoExA item)
        {
            //if (item.ListerKey == "SZ")
            //    Debugger.Break();
            return base.ConvertEntry(item);
        }

        public SevenZipDirectoryLister(IFactory<IDirectoryLister> factory, string listerKey)
            : base(factory, listerKey)
        {
            _convertEntry = (entry) =>
                {
                    if (entry is IInternalFileInfoExA && SevenZipUtils.IsArchive(entry.Name))
                        return new SZEntryInfo(entry as IInternalFileInfoExA);
                    return null;
                };

            _list = (item) =>
            {
                //Remove already created items.
                List<SZEntryInfo> duplicateList = item.List().Intersect(
                    _directoryController.ListTempItems(item.RootWrapper.ArchiveFile.ParseName, item.RelativeMask)).ToList();
                foreach (var info in duplicateList)
                    _directoryController.DeleteTempItems(info);

                return item.List().Union(_directoryController.ListTempItems(item.RootWrapper.ArchiveFile.ParseName, item.RelativeMask));
            };
            _isDirectory = (item) => { return item.CurrentItem.IsDirectory; };

            //_getParent  is defined in GetParent() method.

            _expand = (item, path) =>
                {
                    //TO-DO: Handle password.
                    item.RootWrapper.extract(item.RelativeMask, COFEPath.GetDirectoryName(path), null);
                };

            _createVirtualDirectory = (parent, dirName, type) =>
            {
                if ("7z,zip,".IndexOf(type.ToLower() + ",") == -1)
                    return null;

                dirName = dirName.EndsWith(type, StringComparison.InvariantCultureIgnoreCase) ?
                            dirName : dirName += "." + type; //Add extension if not exists.
                string dirFullPath = COFEPath.Combine(parent.ParseName, dirName);

                using (BinaryWriter newFile = new BinaryWriter(COFEShared.CurrentUserProfile.File.Create(dirFullPath)))
                {
                    switch (type.ToLower())
                    {
                        case "7z": newFile.Write(SevenZipUtils.Empty7z); break;
                        case "zip": newFile.Write(SevenZipUtils.EmptyZip); break;
                        default: return null;
                    }
                }

                IInternalDirectoryInfoExA newArchive = COFEShared.PathParser.TryParsePath(dirFullPath, ParsableType.ParsePath) as IInternalDirectoryInfoExA;
                Assert.IsNotNull(newArchive);

                return new SZEntryInfo((IInternalFileInfoExA)newArchive.GetEmbeddedArchive());

            };
        }
        #endregion

        #region Methods

        public override IInternalDirectoryInfoExA GetParent(IInternalFileSystemInfoExA entry)
        {
            SZEntryInfo embeddedEntry = getEmbeddedItem(entry);

            Assert.IsNotNull(embeddedEntry.RelativePath);

            string parentRelativePath = COFEPath.GetDirectoryName(embeddedEntry.RelativePath);

            if (embeddedEntry.RelativePath == "")
                return embeddedEntry.RootWrapper.ArchiveFile.Parent as IInternalDirectoryInfoExA;

            if (!String.IsNullOrEmpty(parentRelativePath))
            {
                var afi = new ArchiveFileInfo()
                        {
                            FileName = COFEPath.GetDirectoryName(embeddedEntry.CurrentItem.FileName),
                            IsDirectory = true
                        };

                return COFEShared.EntryConstructor.CreateDirectory(
                    this.ListerKey, CreatePropertyProvider(new SZEntryInfo(embeddedEntry.RootWrapper, afi)), EntryConstructionFlags.DefaultWithoutCache);
            }
            else return COFEShared.EntryConstructor.CreateDirectory(
                    this.ListerKey, CreatePropertyProvider(new SZEntryInfo(embeddedEntry.RootWrapper.ArchiveFile)), EntryConstructionFlags.DefaultWithoutCache);



        }

        public override IDirectoryController CreateController()
        {
            _directoryController = new SevenZipDirectoryController(this);
            return _directoryController;
        }

        public override IStreamProvider CreateStreamProvider()
        {
            return new SevenZipStreamProvider(this);
        }

        public override IPropertyProvider CreatePropertyProvider(SZEntryInfo item)
        {
            if (item.CurrentItem.FileName == "")
                return new SevenZipRootPropertyProvider(this, item);
            else return new SevenZipPropertyProvider(this, item);
        }
        #endregion

        #region Data

        private SevenZipDirectoryController _directoryController;

        #endregion

        #region Public Properties

        #endregion



    }
}
